home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / doom / chaserog.zip / SRC_ROG.ZIP / hook.qc < prev    next >
Text File  |  1997-05-02  |  15KB  |  510 lines

  1. //====================================================================
  2. //
  3. // SWINGING GRAPPLING HOOK            by: Perecli Manole AKA Bort
  4. //
  5. //====================================================================
  6. // Aside from this new file, the following are the modifications
  7. // done to id's original source files:
  8. //--------------------------------------------------------------------
  9. // File: Progs.src
  10. // Location: before the "weapons.qc" line
  11. // Added: hook.qc
  12. //--------------------------------------------------------------------
  13. // File: Client.qc
  14. // Procedure: PlayerPostThink
  15. // Location: before line "W_WeaponFrame ();"
  16. // Added: CheckGrapHook ();
  17. //--------------------------------------------------------------------
  18. // File: World.qc
  19. // Procedure: worldspawn
  20. // Location: after line "precache_model ("progs/s_spike.mdl");"
  21. // Added: precache_model ("progs/sw_hook.mdl");
  22. //        precache_model ("progs/chain.mdl");
  23. //--------------------------------------------------------------------
  24. // File: Weapons.qc
  25. // Procedure: W_Precache
  26. // Location: end of procedure
  27. // Added: precache_sound ("shambler/smack.wav");
  28. //        precache_sound ("blob/land1.wav");
  29. //        precache_sound ("hook/chain1.wav");
  30. //        precache_sound ("hook/chain2.wav");
  31. //        precache_sound ("hook/retract.wav");
  32. //--------------------------------------------------------------------
  33. // File: Defs.qc
  34. // Declaration group: player only fields
  35. // Location: after line ".float pain_finished;"
  36. // Added: .float hook;
  37. //--------------------------------------------------------------------
  38.  
  39. /*
  40. Rob;
  41. <hook>.ammo_shells: grading raise/lower
  42. <hook>.ammo_nails:  damageable entity flag
  43. */
  44.  
  45.  
  46. void(vector org, vector vel, float damage) SpawnBlood;    // prototype
  47. float () crandom;                               // prototype
  48.  
  49. // hook bit flags
  50. float    HOOK_ON     = 1;        // set if hook command is active
  51. float HOOK_IN    = 2;        // set if hook has attached
  52. float SHRINK_ON     = 4;        // set if shrink chain is active
  53. float GROW_ON     = 8;        // set if grow chain is active
  54.  
  55. // impulse constants
  56. float I_HOOK         = 98;
  57. float    I_GROW         = 97;
  58. float    I_SHRINK         = 96;
  59. float    I_STOP         = 95;
  60.  
  61. // constants
  62. float MIN_CHAIN_LEN     = 40;        // minimum chain length
  63. float MAX_CHAIN_LEN     = 1000;    // maximum chain length
  64. float CHAIN_LINK_LEN    = 55;        // length between chain link origins
  65.  
  66.  
  67.  
  68. //--------------------------------------------------------------------
  69. // Vector dot product function
  70. //--------------------------------------------------------------------
  71. float (vector from, vector onto) Dot =
  72. {
  73.     return from_x * onto_x + from_y * onto_y + from_z * onto_z;
  74. };
  75.  
  76.  
  77. //--------------------------------------------------------------------
  78. // Removes hook and detaches player
  79. //--------------------------------------------------------------------
  80. void () DropHook =
  81. {
  82.     local entity linkptr, nextptr;
  83.  
  84.     // remove all hook flags
  85.     self.owner.sw_hook = 0;
  86.     sound (self.owner, CHAN_AUTO, "hook/retract.wav", 1, ATTN_NORM);
  87.  
  88.     // removes hook and chain
  89.     linkptr = self.goalentity;
  90.     while (linkptr != world)
  91.     {
  92.         nextptr = linkptr.goalentity;
  93.         remove (linkptr);
  94.         linkptr = nextptr;
  95.     }
  96.     remove( self );
  97.  
  98. };
  99.  
  100.  
  101. //--------------------------------------------------------------------
  102. // Spawn and removes and refreshes chain links
  103. //--------------------------------------------------------------------
  104. void () MaintainLinks =
  105. {
  106.     local vector chainvec,        // vector of the chain
  107.                      p_self_origin,    // predicted future hook origin
  108.                      chainunit;     // vector of chain with distance of 1
  109.     local entity newlink,        // pointer to chain link being added
  110.                      currlink,        // pointer to current link being traversed
  111.                      nextlink;        // pointer to next link after current link
  112.     local float chainlen,        // length of chain
  113.                     currpos,        // numeric position of currlink
  114.                     linknum,        // number of links that should exist
  115.                     linkstart;        // length from hook at which currlink starts
  116.  
  117.     // predicts hook's future position since chain links fall behind
  118.     currpos = vlen(self.velocity) / 22;   // currpos used here just as an intermediate value
  119.     p_self_origin = self.origin + normalize(self.velocity) * currpos;
  120.  
  121.         // get info about chain
  122.  
  123.     // Rob; put 8 units back for appearances in cam view
  124.     if ( (self.dest2_x & CHSCAM_ON) )
  125.     {
  126.         makevectors( self.owner.v_angle );
  127.         chainvec = (((self.owner.origin + '0 0 16') - v_forward * 8) - p_self_origin);
  128.     }
  129.     else
  130.         chainvec = ((self.owner.origin + '0 0 16') - p_self_origin);
  131.  
  132.     chainunit = normalize(chainvec);
  133.     chainvec = chainvec - chainunit * 18;
  134.     chainlen = vlen(chainvec);
  135.  
  136.     currlink = self;
  137.     currpos = 0;
  138.  
  139.     // generate and refresh links
  140.     linknum = ceil(chainlen / CHAIN_LINK_LEN);
  141.     while (currpos < linknum)
  142.     {
  143.         // add entities if chain's length grows
  144.         if (currlink.goalentity == world)
  145.         {
  146.             newlink = spawn();
  147.             newlink.movetype = MOVETYPE_NOCLIP;
  148.             newlink.solid = SOLID_NOT;
  149.             setmodel (newlink, "progs/chain.mdl");
  150.             setsize (newlink, '0 0 0', '0 0 0');
  151.             newlink.goalentity = world;
  152.             currlink.goalentity = newlink;
  153.         }
  154.         currlink = currlink.goalentity;
  155.         currpos = currpos + 1;
  156.  
  157.         // set angles
  158.         currlink.angles = vectoangles(chainvec);
  159.  
  160.         // fixes vectoangles round off error
  161.         if ((currlink.angles_y > 0) && (currlink.angles_y < 180))
  162.             currlink.angles = currlink.angles + '0 1 0';
  163.  
  164.         // vibrates chain links on the z axis
  165.         currlink.angles_z = currlink.angles_z + crandom() * 30;
  166.  
  167.         // set position and frames
  168.         linkstart = (currpos - 1) * CHAIN_LINK_LEN;
  169.         if (currpos < linknum)
  170.         {
  171.             setorigin (currlink, p_self_origin + chainunit * (linkstart + CHAIN_LINK_LEN / 2 ));
  172.             currlink.frame = 9;
  173.         }
  174.         else
  175.         {
  176.             setorigin (currlink, p_self_origin + chainunit * (linkstart + (chainlen - linkstart) / 2 ));
  177.             currlink.frame = floor((chainlen - linkstart) / CHAIN_LINK_LEN * 10);
  178.         }
  179.     }
  180.  
  181.     // remove remaining entities if chain's length shrinks
  182.     nextlink = currlink.goalentity;
  183.     currlink.goalentity = world;
  184.     currlink = nextlink;
  185.     while (currlink != world)
  186.     {
  187.         nextlink = currlink.goalentity;
  188.         remove (currlink);
  189.         currlink = nextlink;
  190.     }
  191. };
  192.  
  193.  
  194. //--------------------------------------------------------------------
  195. // Hook behavior function
  196. //--------------------------------------------------------------------
  197. float GROW_RATE = 16;
  198. float SHRINK_RATE = -20;
  199. void () HookBehavior =
  200. {
  201.     local vector spray;        // for blood
  202.     local vector chainvec;        // chain vector
  203.     local vector velpart;        // player's velocity component moving to or away from hook
  204.     local float chainlen;        // length of extended chain
  205.     //local float framestep;        // grow or shrink step per frame
  206.     local float f1, f2;        // restrainment forces
  207.     local float i1, i2;        // intermediate values
  208.  
  209.     local float gs; // Rob
  210.  
  211.     self.nextthink = time + 0.01;
  212.  
  213.     // decide when to disconnect hook
  214.     if (  !(self.owner.sw_hook & HOOK_ON) ||    // if hook has been retracted
  215.             self.owner.teleport_time > time ||     // if player goes through teleport
  216.             self.owner.solid == SOLID_NOT    ||    // if player dies
  217.             self.enemy.solid == SOLID_NOT    )    // if target dies
  218.     {
  219.         DropHook();
  220.         return;
  221.     }
  222.  
  223.     // give some damage to entities that take damage
  224.     if (self.enemy.takedamage)
  225.     {
  226.         if (time > self.wait)
  227.         {
  228.             T_Damage (self.enemy, self, self.owner, 5);
  229.  
  230.             // when hook hits live entity add blood and sounds
  231.             if (self.enemy.solid == SOLID_SLIDEBOX)
  232.             {
  233.                 // .ammo_nails flag used only here
  234.                 if (! self.ammo_nails)
  235.                 {
  236.                     sound (self, CHAN_AUTO, "shambler/smack.wav", 1, ATTN_NORM);
  237.                     self.ammo_nails = TRUE;
  238.                 }
  239.                 else
  240.                     sound (self, CHAN_AUTO, "blob/land1.wav", 0.8, ATTN_NORM);
  241.                 spray_x = 100 * crandom();
  242.                 spray_y = 100 * crandom();
  243.                 spray_z = 100 * crandom() + 50;
  244.                 SpawnBlood (self.origin, spray, 20);
  245.                 setorigin (self, self.enemy.origin + self.enemy.mins + self.enemy.size * 0.5);
  246.             }
  247.  
  248.             self.wait = time + 0.3;
  249.         }
  250.     }
  251.  
  252.     self.velocity = self.enemy.velocity;
  253.  
  254.     chainvec = self.origin - (self.owner.origin + '0 0 16');
  255.     chainlen = vlen (chainvec);
  256.  
  257. // .ammo_shells = +- amount to size
  258.     gs = self.ammo_shells;
  259.     ////////////////////////////////////////////////
  260.     if ( (self.owner.sw_hook & GROW_ON) )
  261.     {  gs = gs + 2;
  262.         if (gs > GROW_RATE) gs = GROW_RATE;
  263.     }
  264.     else if ( (self.owner.sw_hook & SHRINK_ON) )
  265.     {  gs = gs - 4;
  266.         if (gs < SHRINK_RATE) gs = SHRINK_RATE;
  267.     }
  268.     else
  269.     {
  270.         if (gs > 0)
  271.         {    gs = gs - 2; // fade from grow
  272.             if (gs < 0) gs = 0;
  273.         }
  274.         if (gs < 0)
  275.         {    gs = gs + 4; // fade from shrink
  276.             if (gs > 0) gs = 0;
  277.         }
  278.     }
  279.     self.armorvalue = self.armorvalue + gs;
  280.  
  281.     if (gs > 0)
  282.     {
  283.         if ( (self.owner.flags & FL_ONGROUND) )
  284.             self.armorvalue = chainlen;
  285.         else
  286.         {
  287.             if (self.delay < time)
  288.             {
  289.                 f1 = gs / GROW_RATE;
  290.                 sound (self.owner, CHAN_AUTO, "hook/chain1.wav", f1, ATTN_NORM);
  291.                 self.delay = time + 0.2;
  292.             }
  293.         }
  294.         if ( self.armorvalue > MAX_CHAIN_LEN )
  295.             self.armorvalue = MAX_CHAIN_LEN;
  296.     }
  297.     if (gs < 0)
  298.     {
  299.         // fixes not raising when directly under the hook
  300.         if ( (self.owner.flags & FL_ONGROUND) )
  301.             self.owner.flags = self.owner.flags - FL_ONGROUND;
  302.  
  303.         if (self.armorvalue < MIN_CHAIN_LEN)
  304.             self.armorvalue = MIN_CHAIN_LEN;
  305.         else
  306.         {
  307.             if (self.delay < time)
  308.             {
  309.                 i1 = fabs(gs);
  310.                 i2 = fabs(SHRINK_RATE);
  311.                 f1 = i1 / i2;
  312.                 sound (self.owner, CHAN_AUTO, "hook/chain2.wav", f1, ATTN_NORM);
  313.                 self.delay = time + 0.2;
  314.             }
  315.         }
  316.     }
  317.     ///////////////////////////////////////////////
  318.     self.ammo_shells = gs;
  319.  
  320.  
  321. // chain physics
  322.  
  323.     // if player's location is beyond the chain's reach
  324.     if (chainlen > self.armorvalue)
  325.     {
  326.         // determine player's velocity component of chain vector
  327.         i1 = Dot(self.owner.velocity,chainvec);
  328.         i2 = Dot(chainvec,chainvec);
  329.         velpart = chainvec * (i1 / i2);
  330.  
  331.         // restrainment default force
  332.         f2 = (chainlen - self.armorvalue) * 5;
  333.  
  334.         // if player's velocity heading is away from the hook
  335.         if (Dot(self.owner.velocity,chainvec) < 0)
  336.         {
  337.             if (chainlen > self.armorvalue)
  338.             {
  339.                 self.owner.velocity = self.owner.velocity - (velpart * 0.4);
  340.             }
  341.             // if chain has streched for 25 units
  342.             //if (chainlen > self.armorvalue + 25)
  343.                 // remove player's velocity component moving away from hook
  344.             //    self.owner.velocity = self.owner.velocity - velpart;
  345.             f1 = f2;
  346.         }
  347.         else  // if player's velocity heading is towards the hook
  348.         {
  349.             if (vlen(velpart) < f2)
  350.                 f1 = f2 - vlen(velpart);
  351.             else
  352.                 f1 = 0;
  353.         }
  354.     }
  355.     else
  356.         f1 = 0;
  357.  
  358.     // applys chain restrainment
  359.     self.owner.velocity = self.owner.velocity + normalize(chainvec) * f1;
  360.  
  361.     MaintainLinks ();
  362. };
  363.  
  364.  
  365. //--------------------------------------------------------------------
  366. // Hook's touch function
  367. //--------------------------------------------------------------------
  368. void() HookTouch =
  369. {
  370.     // armorvalue is used to hold current length of chain
  371.     self.armorvalue = vlen(self.origin - (self.owner.origin + '0 0 16'));
  372.  
  373.     // flags hook as being attached to something
  374.     self.owner.sw_hook = self.owner.sw_hook | HOOK_IN;
  375.  
  376.     if (other.solid != SOLID_SLIDEBOX)
  377.     {
  378.         sound (self, CHAN_AUTO, "player/axhit2.wav", 1, ATTN_NORM);
  379.         self.avelocity = '0 0 0';
  380.     }
  381.  
  382.     self.velocity = other.velocity;
  383.  
  384.     self.enemy = other;
  385.     self.think = HookBehavior;
  386.     self.nextthink = time + 0.01;
  387.     self.touch = SUB_Null;
  388.  
  389. };
  390.  
  391.  
  392. //--------------------------------------------------------------------
  393. // Limit hook length during launch
  394. //--------------------------------------------------------------------
  395. void() LaunchHook =
  396. {
  397.     // armorvalue is used to hold current length of chain
  398.     self.armorvalue = vlen(self.origin - (self.owner.origin + '0 0 16'));
  399.  
  400.     if ( !(self.owner.sw_hook & HOOK_ON) ||
  401.             self.armorvalue > MAX_CHAIN_LEN    ||
  402.             self.owner.solid == SOLID_NOT    )
  403.     {
  404.         DropHook();
  405.         return;
  406.     }
  407.  
  408.     MaintainLinks ();
  409.  
  410.     self.nextthink = time + 0.01;
  411. };
  412.  
  413.  
  414. //--------------------------------------------------------------------
  415. // Initiates the hook
  416. //--------------------------------------------------------------------
  417. void(entity myself) InitiateHook =
  418. {
  419.     local entity newhook;
  420.  
  421.     newhook = spawn ();
  422.     newhook.owner = myself;
  423.     newhook.movetype = MOVETYPE_FLY;
  424.     newhook.solid = SOLID_BBOX;
  425.     setmodel (newhook, "progs/sw_hook.mdl");
  426.     setsize (newhook, '0 0 0', '0 0 0');
  427.     makevectors (myself.v_angle);
  428.     setorigin (newhook, myself.origin + (v_forward*16) + '0 0 16' );
  429.     newhook.velocity = v_forward*2000;
  430.     newhook.angles = vectoangles(v_forward);
  431.     newhook.avelocity = '0 0 600';
  432.     sound (myself, CHAN_AUTO, "weapons/ax1.wav", 1, ATTN_NORM);
  433.  
  434.     // used as pointer to first chain link
  435.     newhook.goalentity = world;
  436.  
  437.     // Rob; (reminders 0 init values used)
  438.     // self.wait = 0;  // damage to ents wait cycle
  439.     // self.ammo_shells = 0; // graded shrink/grow variable
  440.     // self.ammo_nails = FALSE;  // initial hit flag for live ents
  441.     // self.delay = 0; // wait cycle for chain raising/lowering sounds
  442.  
  443.     newhook.touch = HookTouch;
  444.     newhook.nextthink = time + 0.01 ;
  445.     newhook.think = LaunchHook;
  446. };
  447.  
  448.  
  449. // called by player jump events (weapons.qc: W_WeaponFrame() )
  450. void() CheckGrapHookJump =
  451. {
  452.     if ( (self.sw_hook & HOOK_IN) )
  453.     {
  454.         if ( (self.flags & FL_JUMPRELEASED) &&    // previous jump cycle has finished
  455.              !(self.flags & FL_ONGROUND) )        // player not on ground
  456.         {
  457.             self.sw_hook = 0; // let hook entity's next think know it's dead
  458.             self.velocity_z = self.velocity_z + 200;
  459.             sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
  460.         }
  461.     }
  462. };
  463.  
  464. //--------------------------------------------------------------------
  465. // Checks impulse
  466. //--------------------------------------------------------------------
  467. void() CheckGrapHook =
  468. {
  469.     if ((!(self.sw_hook & HOOK_ON)) && (self.impulse == I_HOOK))
  470.     {
  471.         // flags hook as being active
  472.         self.sw_hook = HOOK_ON;
  473.  
  474.         InitiateHook (self);
  475.         return;
  476.     }
  477.  
  478.     if (self.sw_hook & HOOK_ON)
  479.     {
  480.         // release hook
  481.         if (self.impulse == I_HOOK)
  482.         {
  483.             self.sw_hook = self.sw_hook - (self.sw_hook & HOOK_ON);
  484.             return;
  485.         }
  486.  
  487.         // deactivate chain growth or shrink
  488.         if (self.impulse == I_STOP)
  489.         {
  490.             self.sw_hook = self.sw_hook - (self.sw_hook & (GROW_ON | SHRINK_ON));
  491.             return;
  492.         }
  493.  
  494.         // activate chain growth
  495.         if (self.impulse == I_GROW)
  496.         {
  497.             self.sw_hook = self.sw_hook | GROW_ON;
  498.             self.sw_hook = self.sw_hook - (self.sw_hook & SHRINK_ON);
  499.             return;
  500.         }
  501.  
  502.         // activate chain shrinking
  503.         if (self.impulse == I_SHRINK)
  504.         {
  505.             self.sw_hook = self.sw_hook | SHRINK_ON;
  506.             self.sw_hook = self.sw_hook - (self.sw_hook & GROW_ON);
  507.         }
  508.     }
  509. };
  510.